# -*- coding: utf-8 -*-
"""
股票移动平均线多头排列分析
找出5日线、10日线、20日线多头排列的股票
"""
import logging
import pandas as pd
from datetime import datetime, timedelta
from database import DatabaseManager
from config import DATABASE_CONFIG

# 配置日志
# 获取项目根目录
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LOG_DIR = os.path.join(PROJECT_ROOT, 'logs')
os.makedirs(LOG_DIR, exist_ok=True)

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(message)s',
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler(os.path.join(LOG_DIR, 'ma_analysis.log'), encoding='utf-8')
    ]
)
logger = logging.getLogger(__name__)

class MAAnalyzer:
    """移动平均线分析器"""
    
    def __init__(self):
        self.db = DatabaseManager(DATABASE_CONFIG)
    
    def get_stock_daily_data(self, stock_code: str, days: int = 30) -> pd.DataFrame:
        """获取股票日线数据"""
        sql = """
        SELECT trade_date, close_price, volume, change_pct
        FROM new_stock_daily 
        WHERE stock_code = %s 
        ORDER BY trade_date DESC 
        LIMIT %s
        """
        try:
            results = self.db.execute_query(sql, (stock_code, days))
            if not results:
                return pd.DataFrame()
            
            df = pd.DataFrame(results)
            df['trade_date'] = pd.to_datetime(df['trade_date'])
            df = df.sort_values('trade_date')  # 按日期升序排列
            return df
        except Exception as e:
            logger.error(f"获取股票 {stock_code} 数据失败: {e}")
            return pd.DataFrame()
    
    def calculate_ma(self, df: pd.DataFrame, periods: list = [5, 10, 20]) -> pd.DataFrame:
        """计算移动平均线"""
        if df.empty or len(df) < max(periods):
            return df
        
        for period in periods:
            df[f'ma{period}'] = df['close_price'].rolling(window=period).mean()
        
        return df
    
    def is_bullish_arrangement(self, df: pd.DataFrame) -> bool:
        """判断是否为多头排列（5日线 > 10日线 > 20日线）"""
        if df.empty or len(df) < 20:
            return False
        
        # 获取最新的移动平均线值
        latest = df.iloc[-1]
        
        # 检查是否有空值
        if pd.isna(latest['ma5']) or pd.isna(latest['ma10']) or pd.isna(latest['ma20']):
            return False
        
        # 多头排列条件：5日线 > 10日线 > 20日线
        return latest['ma5'] > latest['ma10'] > latest['ma20']
    
    def get_all_stock_codes(self) -> list:
        """获取所有活跃股票代码"""
        sql = "SELECT stock_code FROM new_stock_info WHERE status = 'active'"
        try:
            results = self.db.execute_query(sql)
            return [row['stock_code'] for row in results]
        except Exception as e:
            logger.error(f"获取股票代码列表失败: {e}")
            return []
    
    def analyze_bullish_stocks(self) -> pd.DataFrame:
        """分析多头排列的股票"""
        logger.info("开始分析多头排列股票...")
        
        stock_codes = self.get_all_stock_codes()
        if not stock_codes:
            logger.error("未找到任何股票代码")
            return pd.DataFrame()
        
        logger.info(f"共找到 {len(stock_codes)} 只股票，开始分析...")
        
        bullish_stocks = []
        processed = 0
        
        for stock_code in stock_codes:
            try:
                # 获取股票数据
                df = self.get_stock_daily_data(stock_code, 30)
                if df.empty:
                    continue
                
                # 计算移动平均线
                df = self.calculate_ma(df)
                
                # 判断是否为多头排列
                if self.is_bullish_arrangement(df):
                    latest = df.iloc[-1]
                    
                    # 获取股票基本信息
                    stock_info = self.get_stock_info(stock_code)
                    
                    bullish_stocks.append({
                        'stock_code': stock_code,
                        'stock_name': stock_info.get('stock_name', ''),
                        'exchange': stock_info.get('exchange', ''),
                        'industry': stock_info.get('industry', ''),
                        'current_price': latest['close_price'],
                        'ma5': round(latest['ma5'], 2),
                        'ma10': round(latest['ma10'], 2),
                        'ma20': round(latest['ma20'], 2),
                        'change_pct': latest['change_pct'],
                        'volume': latest['volume'],
                        'trade_date': latest['trade_date'].strftime('%Y-%m-%d')
                    })
                
                processed += 1
                if processed % 100 == 0:
                    logger.info(f"已处理 {processed}/{len(stock_codes)} 只股票")
                    
            except Exception as e:
                logger.error(f"分析股票 {stock_code} 失败: {e}")
                continue
        
        logger.info(f"分析完成，共找到 {len(bullish_stocks)} 只多头排列股票")
        return pd.DataFrame(bullish_stocks)
    
    def get_stock_info(self, stock_code: str) -> dict:
        """获取股票基本信息"""
        sql = "SELECT stock_name, exchange, industry FROM new_stock_info WHERE stock_code = %s"
        try:
            results = self.db.execute_query(sql, (stock_code,))
            return results[0] if results else {}
        except Exception as e:
            logger.error(f"获取股票 {stock_code} 基本信息失败: {e}")
            return {}
    
    def save_results(self, df: pd.DataFrame, filename: str = None):
        """保存分析结果"""
        if df.empty:
            logger.warning("没有多头排列的股票数据可保存")
            return
        
        if filename is None:
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f'bullish_stocks_{timestamp}.csv'
        
        try:
            df.to_csv(filename, index=False, encoding='utf-8-sig')
            logger.info(f"分析结果已保存到: {filename}")
        except Exception as e:
            logger.error(f"保存结果失败: {e}")
    
    def print_results(self, df: pd.DataFrame):
        """打印分析结果"""
        if df.empty:
            print("未找到多头排列的股票")
            return
        
        print(f"\n=== 多头排列股票分析结果 ===")
        print(f"共找到 {len(df)} 只多头排列股票")
        print(f"分析时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print("\n股票列表:")
        print("-" * 120)
        print(f"{'代码':<8} {'名称':<12} {'交易所':<6} {'行业':<20} {'当前价':<8} {'5日线':<8} {'10日线':<8} {'20日线':<8} {'涨跌幅':<8} {'成交量':<12} {'日期':<12}")
        print("-" * 120)
        
        for _, row in df.iterrows():
            print(f"{row['stock_code']:<8} {row['stock_name']:<12} {row['exchange']:<6} "
                  f"{str(row['industry'])[:18]:<20} {row['current_price']:<8.2f} "
                  f"{row['ma5']:<8.2f} {row['ma10']:<8.2f} {row['ma20']:<8.2f} "
                  f"{row['change_pct']:<8.2f} {row['volume']:<12} {row['trade_date']:<12}")
        
        print("-" * 120)
        
        # 按行业统计
        if 'industry' in df.columns:
            industry_stats = df['industry'].value_counts()
            print(f"\n按行业分布:")
            for industry, count in industry_stats.head(10).items():
                print(f"  {industry}: {count} 只")
        
        # 按交易所统计
        if 'exchange' in df.columns:
            exchange_stats = df['exchange'].value_counts()
            print(f"\n按交易所分布:")
            for exchange, count in exchange_stats.items():
                print(f"  {exchange}: {count} 只")

def main():
    """主函数"""
    try:
        analyzer = MAAnalyzer()
        
        # 分析多头排列股票
        bullish_df = analyzer.analyze_bullish_stocks()
        
        # 打印结果
        analyzer.print_results(bullish_df)
        
        # 保存结果
        analyzer.save_results(bullish_df)
        
    except Exception as e:
        logger.error(f"分析过程出错: {e}")
        raise

if __name__ == "__main__":
    main()
